#pragma once
#include <iostream>
#include <pthread.h>
#include "Socket.hpp" // 引入套接字封装类
#include <sys/types.h>
#include <sys/socket.h>
#include <fstream> // 文件操作：读取HTML资源
#include <vector>  // 存储请求头
#include <sstream> // 字符串流：解析请求
using namespace std;

// 服务器配置常量
static const int defaultport = 8085;  // 默认端口
const string wwwroot = "./wwwroot";   // 网站根目录：存放HTML等静态资源
const string sep = "\r\n";            // HTTP协议换行符（\r\n）
const string homepage = "index.html"; // 默认主页文件名

class HTTPServer; // 前置声明：避免循环依赖

// ThreadData类：线程数据载体
// 作用：多线程处理时，向线程函数传递客户端通信套接字等数据
class ThreadData
{
public:
    // 构造函数：传递套接字和服务器指针
    ThreadData(int fd, HTTPServer *httpsvr)
        : _sockfd(fd), _httpsvr(httpsvr) {}
    ThreadData(int fd) : _sockfd(fd) {}

public:
    int _sockfd;          // 客户端通信套接字
    HTTPServer *_httpsvr; // 服务器指针（预留扩展）
};

// HTTPRequest类：解析HTTP请求
// 作用：将客户端发送的原始HTTP请求字符串解析为结构化数据（方法、URL、正文等）
class HTTPRequest
{
public:
    // 反序列化：将原始请求字符串拆分为请求头和正文
    // 逻辑：HTTP请求格式为“请求头\r\n\r\n请求正文”，通过\r\n分割提取
    void deserialize(string req)
    {
        while (1)
        {
            size_t pos = req.find(sep); // 查找\r\n分隔符
            if (pos == string::npos)
                break;                       // 无分隔符：解析结束
            string tmp = req.substr(0, pos); // 提取一行请求头
            if (tmp.empty())
                break;                      // 空行：请求头结束，剩余为正文
            req_header.push_back(tmp);      // 保存请求头行
            req.erase(0, pos + sep.size()); // 移除已处理部分
        }
        text = req; // 剩余内容为请求正文（POST参数在这里）
    }

    // 解析请求：从请求头中提取关键信息（方法、URL、文件路径等）
    // 逻辑：HTTP请求首行为“方法 URL 版本”，据此确定要返回的资源
    void prase()
    {
        stringstream ss(req_header[0]);         // 用字符串流解析首行
        ss >> _method >> _url >> _http_version; // 提取方法（GET/POST）、URL、版本
        _file_path = wwwroot;                   // 基础路径：网站根目录
        // 如果访问根目录或主页，则指向默认主页
        if (_url == "/" || _url == "/index.html")
        {
            _file_path += "/";
            _file_path += homepage; // 最终路径：./wwwroot/index.html
        }
        else
            _file_path += _url; // 其他URL：直接拼接（如/a/b/hello.html→./wwwroot/a/b/hello.html）
    }

    // 调试打印：输出解析结果（辅助开发）
    void DeBugPrint()
    {
        for (auto &line : req_header)
            cout << line << "\n";
        cout << "------------------------------解析结果------------------------------\n";
        cout << "method: " << _method << endl;             // 请求方法（GET/POST）
        cout << "url: " << _url << endl;                   // 请求URL
        cout << "http version: " << _http_version << endl; // HTTP版本
        cout << "file path: " << _file_path << endl;       // 资源文件路径
        cout << text << endl;                              // 请求正文（POST参数在这里）
    }

public:
    vector<string> req_header; // 存储请求头所有行
    string text;               // 存储请求正文（POST参数）

    // 解析结果
    string _method;       // 请求方法（GET/POST）
    string _url;          // 请求的URL
    string _http_version; // HTTP版本（如HTTP/1.1）
    string _file_path;    // 要访问的本地文件路径
};

// HTTPServer类：HTTP服务器主体
// 作用：启动服务器、接受客户端连接、创建线程处理请求、返回响应
class HTTPServer
{
public:
    // 构造函数：初始化服务器端口
    HTTPServer(int port = defaultport) : _port(port) {}
    ~HTTPServer() {}

    // 读取HTML文件内容（静态方法：无状态，可直接调用）
    // 逻辑：根据文件路径读取内容，用于构建响应
    static string readHTMLcontent(const string &htmlpath)
    {
        ifstream in(htmlpath); // 打开文件
        if (!in.is_open())
            return "404 Not Found"; // 文件不存在：返回404
        string content;
        string line;
        while (getline(in, line))
            content += line; // 逐行读取内容
        in.close();
        return content; // 返回文件内容
    }

    // 处理HTTP请求（静态方法：作为线程函数的回调，处理单个客户端请求）
    // 逻辑：接收请求→解析请求→读取资源→返回响应→关闭连接
    static void handlerhttp(int sockfd)
    {
        char buffer[10240]; // 缓冲区：存储客户端发送的原始请求
        // 接收请求：recv返回接收的字节数（>0表示成功）
        ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            buffer[n] = '\0'; // 手动添加字符串结束符
            cout << "..........................客户端原始请求..........................\n" << buffer << endl; // 打印原始请求（调试用）

            // 解析请求
            cout << "..........................客户端请求解析后.........................." << endl;
            HTTPRequest req;
            req.deserialize(buffer); // 拆分请求头和正文
            req.prase();             // 提取方法、URL等
            req.DeBugPrint();        // 打印解析结果（调试用）

            // 构建响应：读取请求的资源文件
            string text = readHTMLcontent(req._file_path); // 资源内容
            // HTTP响应格式：状态行\r\n响应头\r\n\r\n正文
            string status_line = "HTTP/1.0 200 OK\r\n";                                    // 状态行：成功
            string response_header = "Content-Length: " + to_string(text.size()) + "\r\n"; // 响应头：内容长度
            string blank_line = "\r\n";                                                    // 空行：分隔头和正文
            string response = status_line + response_header + blank_line + text;           // 完整响应

            // 发送响应给客户端
            send(sockfd, response.c_str(), response.size(), 0);
        }
        close(sockfd); // 处理完毕，关闭通信套接字
    }

    // 线程入口函数（静态方法：符合pthread_create要求）
    // 逻辑：分离线程→获取客户端数据→调用请求处理函数→释放资源
    static void *ThreadRun(void *args)
    {
        pthread_detach(pthread_self());                   // 线程分离：结束后自动释放资源
        ThreadData *td = static_cast<ThreadData *>(args); // 转换线程数据
        handlerhttp(td->_sockfd);                         // 处理该客户端的请求
        delete td;                                        // 释放线程数据
        return nullptr;
    }

    // 启动服务器
    // 逻辑：初始化套接字→绑定端口→启动监听→循环接受连接→创建线程处理
    bool start()
    {
        // 1. 初始化监听套接字
        _listen_sockfd.Socket();    // 创建套接字
        _listen_sockfd.Bind(_port); // 绑定端口
        _listen_sockfd.Listen();    // 启动监听

        // 2. 服务器主循环：持续接受客户端连接
        while (1)
        {
            string clientip;
            uint16_t clientport;
            // 接受客户端连接：返回通信套接字
            int communication_sockfd = _listen_sockfd.Accept(&clientport, &clientip);
            if (communication_sockfd < 0)
                continue; // 接受失败：继续等待下一个

            log(Info, "get a linking, communication_sockfd: %d", communication_sockfd); // 记录新连接

            // 3. 创建线程处理该连接（并发处理多客户端）
            pthread_t tid;
            ThreadData *td = new ThreadData(communication_sockfd); // 封装通信套接字
            pthread_create(&tid, nullptr, ThreadRun, td);          // 创建线程
        }
    }

private:
    Sock _listen_sockfd; // 监听套接字：负责接受客户端连接
    uint16_t _port;      // 服务器端口
};